﻿using RPCServer.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RPCServer.Core
{
    [MObject(IsFromPool = true)]
    class MBuffer
    {
        static MBuffer _emptyBuffer;
        public static MBuffer EmptyBuffer
        {
            get
            {
                if(_emptyBuffer == null)
                {
                    _emptyBuffer = new();
                    _emptyBuffer.SetBuffer(null, 0, 0);
                }
                return _emptyBuffer;
            }
        }

        byte[] _buffer;

        int _orign;
        /// <summary>
        /// 当前待写入位置
        /// </summary>
        int _writePoint;
        /// <summary>
        /// 当前待读取位置
        /// </summary>
        int _readPoint;
        int _capcity;

        public int Offset => _writePoint;
        public byte[] Buffer => _buffer;
        public int Size => _capcity;
        //public int Offset
        //{
        //    get
        //    {
        //        return _offset - _orign;
        //    }
        //    set
        //    {
        //        int offset = _orign + value;
        //        _offset = offset < _orign ? _orign : offset;
        //    }
        //}

        //public bool IsEmpty => _offset == _end;

        //public int Count => _end - _offset + _capcity;

        public int FreeSize => _capcity - _writePoint;
        public int Count => _writePoint - _readPoint;

        public bool IsEmpty { get; set; }

        public void Clear()
        {
            _writePoint = _orign;
            _readPoint = _orign;
        }

        public void SetBuffer(byte[] buffer, int offset, int count)
        {
            _buffer = buffer;
            _orign = offset;
            _capcity = count;
            Clear();
        }

        public void SetData(byte[] buffer, int offset, int count)
        {
            _buffer = buffer;
            _orign = offset;
            _capcity = count;
            _readPoint = _orign;
            _writePoint = _capcity;
        }

        public void SetBuffer(byte[] buffer)
        {
            SetBuffer(buffer, 0, buffer.Length);
        }

        public void Write(byte[] data)
        {
            Write(data, 0, data.Length);
        }

        public void Write(byte[] data, int offset, int count)
        {
            if (FreeSize >= count)
            {
                Array.Copy(data, offset, _buffer, _writePoint, count);
                _writePoint += count;
            }
            else
            {
                Console.WriteLine("==== 写入 ParserBuffer Fail!!!!");
            }
        }

        public void WriteInt32(int value)
        {
            Write(BitConverter.GetBytes(value));
        }

        public void WriteString(string str)
        {
            Write(Encoding.UTF8.GetBytes(str));
        }

        public void Write(MBuffer buffer)
        {
            buffer.Read(_buffer, _readPoint, FreeSize);
        }

        public bool Read(byte[] distance,int offset,int count)
        {
            if(Count > 0)
            {
                int newCount = count > Count ? Count : count;
                Array.Copy(_buffer, _readPoint, distance, offset, newCount);
                return true;
            }
            return false;
        }

        public bool TryReadInt32(out int value)
        {
            if (Count >= 4)
            {
                value = BitConverter.ToInt32(_buffer, _readPoint);
                _readPoint += 4;
                return true;
            }
            value = default;
            return false;
        }

        public bool TryReadString(out string value)
        {
            if (Count > 0)
            {
                value = Encoding.UTF8.GetString(_buffer, _readPoint, Count);
                _readPoint += Count;
                return true;
            }
            value = default;
            return false;
        }

        public bool TryReadByte(out byte value)
        {
            if (Count > 0)
            {
                value = _buffer[_readPoint++];
                return true;
            }
            value = default;
            return false;
        }

        void Tidy()
        {

        }
    }
}
